home *** CD-ROM | disk | FTP | other *** search
/ Amiga Collections: Camelot / Camelot 105 (1991-02)(Swedish User Group of Amiga)(SE)(PD)[WB].zip / Camelot 105 (1991-02)(Swedish User Group of Amiga)(SE)(PD)[WB].adf / AmigaUUCP / dnews / main.c < prev    next >
C/C++ Source or Header  |  1991-02-14  |  13KB  |  620 lines

  1.  
  2. /*
  3.  *  MAIN.C
  4.  */
  5.  
  6. #include "defs.h"
  7.  
  8. #define MSTLEN    64    /*  # of forward referenced articles    */
  9.  
  10. char    User[32];
  11. NGroup    *GBase;
  12. NGroup    *CurGroup;
  13. void    *GrpDisp;
  14. void    *HelpDisp;
  15. void    *DataDisp;
  16. void    *ScanDisp;    /*  subject scan display    */
  17. char    *GroupFile = "T:DNews_Groups";
  18. char    *HelpFile = "T:DNews_Help";
  19. char    TmpBuf[TMPBSIZE];
  20.  
  21. long    MStack[MSTLEN];
  22. short    Mi;
  23. short    Mx;
  24. short    ShowAllGroups = 0;
  25.  
  26. #ifndef LATTICE
  27. void *GfxBase;
  28. void *IntuitionBase;
  29. #endif
  30.  
  31. Prototype char *FileForArticle(NGroup *, int);
  32. Prototype void SetGroup(NGroup *);
  33. Prototype void SetCurNo(NGroup *, int);
  34. Prototype int NumUnreadArticles(NGroup *);
  35.  
  36. Local NGroup *FindGroupByIndex(int);
  37. Local void HandleKey(int);
  38. Local void UpdateGroupList(char *);
  39. Local void CreateHelpFile();
  40.  
  41. Local char *TitleForArticle(NGroup *);
  42.  
  43. IDENT(".03");
  44.  
  45. int
  46. brk()
  47. {
  48.     return(0);
  49. }
  50.  
  51. void
  52. closlib()
  53. {
  54.     if (GfxBase) {
  55.     CloseLibrary(GfxBase);
  56.     GfxBase = NULL;
  57.     }
  58.     if (IntuitionBase) {
  59.     CloseLibrary(IntuitionBase);
  60.     IntuitionBase = NULL;
  61.     }
  62. }
  63. main(ac, av)
  64. char **av;
  65. {
  66.     onbreak(brk);
  67.     atexit(closlib);
  68.  
  69.     IntuitionBase = OpenLibrary("intuition.library", 0);
  70.     GfxBase = OpenLibrary("graphics.library", 0);
  71.     if (IntuitionBase == NULL || GfxBase == NULL) {
  72.     puts("unable to open libraries");
  73.     exit(20);
  74.     }
  75.  
  76.     FindUser(User, sizeof(User));   /*  who am I ?  */
  77.     LoadGroups(User);               /*  load newsrc for user    */
  78.     LoadKillFile(User);
  79.     if (GBase == NULL) {
  80.     CreateNewsrc(User);
  81.     LoadGroups(User);
  82.     if (GBase == NULL) {
  83.         printf("Unable to find any news!\n");
  84.         exit(1);
  85.     }
  86.     }
  87.  
  88.     LoadDisplayConfig();
  89.  
  90.     UpdateGroupList(GroupFile);
  91.     GrpDisp = OpenBrowseDisplay(GroupFile, "h-help", 0);
  92.     if (GrpDisp == NULL) {
  93.     puts("unable to open window");
  94.     exit(1);
  95.     }
  96.  
  97.     /*
  98.      *    Handle browse events
  99.      */
  100.  
  101.     {
  102.     void *disp;
  103.     int row;
  104.     int col;
  105.     NGroup *grp;
  106.  
  107.     while (WaitBrowseEvent(&disp, &row, &col)) {
  108.         if (disp == GrpDisp) {      /*  handle main group list  */
  109.         if (row == -1) {        /*  close window    */
  110.             if (col == -1)
  111.             break;
  112.             HandleKey(col);
  113.             continue;
  114.         }
  115.         if (grp = FindGroupByIndex(row))
  116.             SetGroup(grp);
  117.         continue;
  118.         }
  119.         if (disp == HelpDisp) {
  120.         if (row == -1) {
  121.             if (col == -1) {
  122.             CloseBrowseDisplay(HelpDisp);
  123.             HelpDisp = NULL;
  124.             }
  125.         }
  126.         continue;
  127.         }
  128.         if (disp == DataDisp) {
  129.         if (row == -1) {
  130.             if (col == -1) {
  131.             CloseBrowseDisplay(DataDisp);
  132.             DataDisp = NULL;
  133.             SetGroup(NULL);
  134.             continue;
  135.             }
  136.             HandleKey(col);
  137.             continue;
  138.         }
  139.         }
  140.     }
  141.     }
  142.  
  143.     if (GrpDisp)
  144.     CloseBrowseDisplay(GrpDisp);
  145.     if (HelpDisp)
  146.     CloseBrowseDisplay(HelpDisp);
  147.     if (DataDisp)
  148.     CloseBrowseDisplay(DataDisp);
  149.     if (ScanDisp)
  150.     CloseBrowseDisplay(ScanDisp);
  151.     SaveKillFile(User);
  152.     UnloadGroups(User);
  153.     SaveDisplayConfig();
  154.     remove(GroupFile);
  155.     return(0);
  156. }
  157.  
  158. static void
  159. UpdateGroupList(file)
  160. char *file;
  161. {
  162.     FILE *fi;
  163.     NGroup *grp;
  164.  
  165.     fi = fopen(file, "w");
  166.     if (fi == NULL)
  167.     return;
  168.  
  169.     for (grp = GBase; grp; grp = grp->Next) {
  170.     long unread;
  171.  
  172.     if (grp->Enabled == 0) {
  173.         grp->Unread = 0;
  174.         continue;
  175.     }
  176.     grp->Unread = NumUnreadArticles(grp);
  177.     if (grp->Unread > 0 || ShowAllGroups)
  178.         fprintf(fi, "%-3d %-20s\n", NumUnreadArticles(grp), grp->Name);
  179.     }
  180.     fclose(fi);
  181. }
  182.  
  183. static void
  184. HandleKey(key)
  185. {
  186.     NGroup *grp = CurGroup;
  187.     int n;
  188.  
  189.     for (;;) {
  190.     if (key != 'm' && key != 'M') {
  191.         Mi = 0;
  192.         Mx = 0;
  193.     }
  194.  
  195.     switch(key) {
  196.     case 'A':
  197.         ShowAllGroups = ~ShowAllGroups;
  198.         SetGroup(NULL);
  199.         break;
  200.     case 'h':
  201.         if (HelpDisp == NULL) {
  202.         CreateHelpFile();
  203.         HelpDisp = OpenBrowseDisplay(HelpFile, "HELP", 2);
  204.         }
  205.         break;
  206.     case 'v':       /*  first unread article    */
  207.         if (grp) {
  208.         n = NextNotInRange(grp->RList, 0);
  209.         if (n >= grp->MaxNo + 1)
  210.             n = grp->MaxNo;
  211.         grp->CurNo = n - 1;
  212.         /* SetCurNo(grp, n - 1); */
  213.         key = 's';
  214.         continue;
  215.         }
  216.         break;
  217.     case 'M':       /*  next reference auto-rewind          */
  218.     case 'm':       /*  next reference                      */
  219.         /*
  220.          *    Find an article that references this one.
  221.          */
  222.         if (grp->CurNo < grp->MaxNo)
  223.         RangeAdd(&grp->RList, grp->CurNo, grp->CurNo);
  224.  
  225.         if (grp) {
  226.         char *ref;
  227.         short alloced = 0;
  228.  
  229.         if (Mi || Mx == 0) {
  230.             ref = NewsMessageIdOf(grp, grp->CurNo);
  231.         } else {
  232.             short i;
  233.             char *tmp;
  234.  
  235.             ref = NULL;
  236.             if (tmp = ReferenceLineOf(grp, grp->CurNo)) {
  237.             for (i = Mx; i > 0; --i) {
  238.                 ref = NextRef(&tmp);
  239.                 if (ref == NULL)
  240.                 break;
  241.             }
  242.             }
  243.             if (ref) {
  244.             ref = strdup(ref);
  245.             alloced = 1;
  246.             }
  247.         }
  248.         if (ref) {
  249.             for (n = NextNotInRange(grp->RList, grp->CurNo); n < grp->MaxNo; n = NextNotInRange(grp->RList, n)) {
  250.             if (FindArticleReferencing(grp, ref, n))
  251.                 break;
  252.             }
  253.             if (alloced)
  254.             free(ref);
  255.             if (n >= grp->MaxNo) {      /*  no more references  */
  256.             if (Mi) {               /*  try refs to previous articles on the same line */
  257.                 n = MStack[--Mi];
  258.                 grp->CurNo = n;
  259.                 /* SetCurNo(grp, n); */
  260.                 continue;        /*  w/ same key */
  261.             }
  262.             ++Mx;            /*  try References: fields of original    */
  263.             continue;        /*  w/ same key */
  264.             }
  265.             if (Mi != MSTLEN)
  266.             MStack[Mi++] = n;
  267.             SetCurNo(grp, n);
  268.         } else {
  269.             Mx = 0;
  270.             Mi = 0;
  271.             if (key == 'M') {
  272.             key = 'v';
  273.             continue;
  274.             }
  275.         }
  276.         }
  277.         break;
  278.     case 'g':
  279.         if (grp) {
  280.         FILE *fi;
  281.         long artno = -1;
  282.         if (fi = fopen("CON:0/0/200/50/Article?", "w+")) {
  283.             fprintf(fi, ": ");
  284.             fflush(fi);
  285.             if (fgets(TmpBuf, sizeof(TmpBuf), fi))
  286.             artno = atoi(TmpBuf);
  287.             fclose(fi);
  288.         }
  289.         if (artno < 0)
  290.             artno = 0;
  291.         if (artno > grp->MaxNo)
  292.             artno = grp->MaxNo;
  293.         SetCurNo(grp, artno);
  294.         RangeDel(&grp->RList, artno, artno);
  295.         }
  296.         break;
  297.     case 'n':       /*  mark and go to next article         */
  298.     case '.':
  299.     case '>':
  300.         if (grp->CurNo < grp->MaxNo)
  301.         RangeAdd(&grp->RList, grp->CurNo, grp->CurNo);
  302.     case 's':       /*  do not mark and go to next article  */
  303.         grp->CurNo = NextNotInRange(grp->RList, grp->CurNo);
  304.         /* SetCurNo(grp, NextNotInRange(grp->RList, grp->CurNo)); */
  305.         if (grp->CurNo >= grp->MaxNo + 1) {
  306.         grp->CurNo = grp->MaxNo;
  307.         } else {
  308.         /*
  309.          *  skip past killed or non-existant articles, marking them as
  310.          *  we go
  311.          */
  312.  
  313.         if (ArticleRefKilled(grp, grp->CurNo)) {
  314.             RangeAdd(&grp->RList, grp->CurNo, grp->CurNo);
  315.             key = 's';
  316.             continue;
  317.         }
  318.         }
  319.         SetCurNo(grp, grp->CurNo);
  320.         break;
  321.     case 'b':
  322.     case '<':
  323.         if (grp) {
  324.         if (grp->CurNo == grp->PrevNo[0]) {
  325.             movmem(grp->PrevNo + 1, grp->PrevNo, sizeof(grp->PrevNo) - sizeof(grp->PrevNo[0]));
  326.             grp->PrevNo[arysize(grp->PrevNo)-1] = 0;
  327.         }
  328.         if (grp->PrevNo[0]) {
  329.             SetCurNo(grp, -grp->PrevNo[0]);
  330.             movmem(grp->PrevNo + 1, grp->PrevNo, sizeof(grp->PrevNo) - sizeof(grp->PrevNo[0]));
  331.             grp->PrevNo[arysize(grp->PrevNo)-1] = 0;
  332.         } else if (grp->CurNo > 1) {
  333.             SetCurNo(grp, -(grp->CurNo - 1));
  334.         }
  335.         if (grp->CurNo)
  336.             RangeDel(&grp->RList, grp->CurNo, grp->CurNo);
  337.         }
  338.         break;
  339.     case 'k':       /*  kill followups to this article and go to next article */
  340.         if (grp->CurNo < grp->MaxNo)
  341.         RangeAdd(&grp->RList, grp->CurNo, grp->CurNo);
  342.         if (grp) {
  343.         char *ref;
  344.         if (ref = NewsMessageIdOf(grp, grp->CurNo))
  345.             AddKillFile(ref, 0, 0);
  346.         if (ref = ReferenceLineOf(grp, grp->CurNo))
  347.             AddKillFile(ref, 0, 0);
  348.         if (ref = SubjectOf(grp, grp->CurNo, 1))
  349.             AddKillFile(ref, 0, 1);
  350.         }
  351.         key = 'n';
  352.         continue;
  353.     case 'K':       /*  kill followups for 30 days  */
  354.         if (grp->CurNo < grp->MaxNo)
  355.         RangeAdd(&grp->RList, grp->CurNo, grp->CurNo);
  356.         if (grp) {
  357.         char *ref;
  358.         if (ref = NewsMessageIdOf(grp, grp->CurNo))
  359.             AddKillFile(ref, 30, 0);
  360.         if (ref = ReferenceLineOf(grp, grp->CurNo))
  361.             AddKillFile(ref, 30, 0);
  362.         if (ref = SubjectOf(grp, grp->CurNo, 1))
  363.             AddKillFile(ref, 30, 1);
  364.         }
  365.         key = 'n';
  366.         continue;
  367.     case 'U':       /*  unkill followups            */
  368.         if (grp) {
  369.         char *ref;
  370.         if (ref = NewsMessageIdOf(grp, grp->CurNo))
  371.             RemKillFile(ref);
  372.         if (ref = ReferenceLineOf(grp, grp->CurNo))
  373.             RemKillFile(ref);
  374.         }
  375.         break;
  376.     case CTRL('g'): /*  goto specific article and mark as unread    */
  377.         break;
  378.     case '=':       /*  bring up subject scan window                */
  379.         break;
  380.     case '/':       /*  search in article               */
  381.         break;
  382.     case CTRL('/'): /*  search in all remaining articles*/
  383.         break;
  384.     case 'w':       /*  write article to file   */
  385.         if (grp) {
  386.         char *fn;
  387.  
  388.         if (fn = GetFileName(0)) {
  389.             FILE *fi = fopen(FileForArticle(grp, grp->CurNo), "r");
  390.             FILE *fo = fopen(fn, "w");
  391.             long n;
  392.  
  393.             if (fi && fo) {
  394.             while ((n = fread(TmpBuf, 1, sizeof(TmpBuf), fi)) > 0)
  395.                 fwrite(TmpBuf, 1, n, fo);
  396.             }
  397.             if (fi)
  398.             fclose(fi);
  399.             if (fo)
  400.             fclose(fo);
  401.         }
  402.         }
  403.         break;
  404.     case 'r':       /*  reply to sender         */
  405.     case 'R':       /*  w/ text of current art  */
  406.         if (grp)
  407.         ReplyArticle(key, grp);
  408.         break;
  409.     case 'f':       /*  followup to newsgroup   */
  410.     case 'F':       /*  w/ text of current art  */
  411.         if (grp)
  412.         FollowUpArticle(key, grp);
  413.         break;
  414.     case 'p':       /*  post article (asynch)   */
  415.         PostArticle(grp);       /*  grp can be NULL!    */
  416.         break;
  417.     case 'N':
  418.         {
  419.         if (grp)
  420.             grp = grp->Next;
  421.  
  422.         while (grp && NumUnreadArticles(grp) == 0)
  423.             grp = grp->Next;
  424.  
  425.         if (grp == NULL) {
  426.             grp = GBase;
  427.             while (grp && NumUnreadArticles(grp) == 0)
  428.             grp = grp->Next;
  429.         }
  430.         if (grp == NULL)    /*  set to NULL?    */
  431.             grp = GBase;
  432.  
  433.         SetGroup(grp);
  434.         }
  435.         break;
  436.     case 'P':
  437.         {
  438.         if (grp)
  439.             grp = PrevGroup(grp);
  440.  
  441.         while (grp && NumUnreadArticles(grp) == 0)
  442.             grp = PrevGroup(grp);
  443.  
  444.         if (grp == NULL) {
  445.             grp = LastGroup();
  446.             while (grp && NumUnreadArticles(grp) == 0)
  447.             grp = PrevGroup(grp);
  448.         }
  449.         if (grp == NULL)    /*  set to NULL?    */
  450.             grp = LastGroup();
  451.  
  452.         SetGroup(grp);
  453.         }
  454.         break;
  455.     default:
  456.         break;
  457.     }
  458.     break;
  459.     }
  460.     if (DataDisp && grp && (grp->Flags & GROUPF_REDISPLAY)) {
  461.     grp->Flags &= ~GROUPF_REDISPLAY;
  462.     ChangeBrowseDisplay(DataDisp, FileForArticle(grp, grp->CurNo), TitleForArticle(grp));
  463.     }
  464. }
  465.  
  466. static NGroup *
  467. FindGroupByIndex(i)
  468. {
  469.     NGroup *grp;
  470.  
  471.  
  472.     for (grp = GBase; grp && i > 0; grp = grp->Next) {
  473.     if (grp->Enabled == 0)
  474.         continue;
  475.     if (grp->Unread > 0 || ShowAllGroups)
  476.         --i;
  477.     }
  478.     return(grp);
  479. }
  480.  
  481.  
  482. char *
  483. FileForArticle(grp, artno)
  484. NGroup *grp;
  485. {
  486.     static char buf[256];
  487.  
  488.     sprintf(buf, "%s/%d", grp->Name, artno);
  489.  
  490.     return(MakeConfigPath(UUNEWS, buf));
  491. }
  492.  
  493. void
  494. CreateHelpFile()
  495. {
  496.     FILE *fi;
  497.     if (fi = fopen(HelpFile, "w")) {
  498.     fputs(
  499.         "use mouse buttons to select newsgroup\n"
  500.         "\n"
  501.         "h  -help\n"
  502.         "v  -first unread article (usually after m's)\n"
  503.         "m  -mark article read and follow references, stop at end\n"
  504.         "M  -mark article read and follow references, 'v' at end\n"
  505.         "n  -mark article read and goto next\n"
  506.         "s  -do not mark and goto next unread\n"
  507.         "b  -backup to previously read article\n"
  508.         "k  -kill refs to article (this session only)\n"
  509.         "K  -kill refs to article for 30 days\n"
  510.         "U  -unkill refs to article\n"
  511.         "w  -write article to file\n"
  512.         "r  -reply to sender of article\n"
  513.         "R  -reply to sender, include article contents\n"
  514.         "f  -followup to newsgroup\n"
  515.         "F  -followup to newsgroup, include article contents\n"
  516.         "p  -post a new article\n"
  517.         "N  -NEXT GROUP\n"
  518.         "P  -PREV GROUP\n"
  519.  
  520.         "4  -left half of article\n"
  521.         "6  -right half of article\n"
  522.         "8  -page up\n"
  523.         "2  -page down (SPACE also pages down)\n"
  524.         "3  -bottom of article\n"
  525.         "9  -top of article\n"
  526.  
  527.         "   -(space) page down\n"
  528.         "CR -(return) two lines down\n"
  529.  
  530.         "\n", fi
  531.     );
  532.     fclose(fi);
  533.     }
  534. }
  535.  
  536. char *
  537. TitleForArticle(grp)
  538. NGroup *grp;
  539. {
  540.     char *fname = FileForArticle(grp, grp->CurNo);
  541.     char *ptr;
  542.  
  543.     ptr = fname + strlen(fname);
  544.  
  545.     while (ptr > fname && *ptr != '/')
  546.     --ptr;
  547.     --ptr;
  548.     while (ptr >= fname && *ptr != '/')
  549.     --ptr;
  550.     ++ptr;
  551.  
  552.     sprintf(TmpBuf, "%s (%d)", ptr, grp->MaxNo - 1);
  553.     return(TmpBuf);
  554. }
  555.  
  556.  
  557. void
  558. SetGroup(grp)
  559. NGroup *grp;
  560. {
  561.     if (CurGroup)
  562.     ClearGroupCache(CurGroup);
  563.     if (grp) {
  564.     CurGroup = grp;
  565.     Mi = 0;
  566.     Mx = 0;
  567.     if (DataDisp)
  568.         ChangeBrowseDisplay(DataDisp, FileForArticle(grp, grp->CurNo), TitleForArticle(grp));
  569.     else
  570.         DataDisp = OpenBrowseDisplay(FileForArticle(grp, grp->CurNo), TitleForArticle(grp), 1);
  571.     }
  572.     /*
  573.      *    ChangeBrowseDisplay() closes file so we can update it, only openning
  574.      *    it again when actually scanned on a display refresh.
  575.      */
  576.     ChangeBrowseDisplay(GrpDisp,GroupFile,"h-help");
  577.     UpdateGroupList(GroupFile);
  578.     RefreshBrowseDisplay(GrpDisp);
  579. }
  580.  
  581. void
  582. SetCurNo(grp, n)
  583. NGroup *grp;
  584. int n;
  585. {
  586.     short addbkup = 1;
  587.     int oldno = grp->CurNo;
  588.  
  589.     if (n < 0) {
  590.     n = -n;
  591.     addbkup = 0;
  592.     }
  593.  
  594.     grp->Flags |= GROUPF_REDISPLAY;
  595.     grp->CurNo = n;
  596.  
  597.     if (addbkup && oldno && grp->PrevNo[0] != oldno) {
  598.     movmem(grp->PrevNo, grp->PrevNo + 1, sizeof(grp->PrevNo) - sizeof(grp->PrevNo[0]));
  599.     grp->PrevNo[0] = oldno;
  600.     }
  601. }
  602.  
  603. int
  604. NumUnreadArticles(grp)
  605. NGroup *grp;
  606. {
  607.     int n = grp->MaxNo - 1;
  608.  
  609.     if (grp) {
  610.     Range *ran;
  611.  
  612.     for (ran = grp->RList; ran; ran = ran->Next)
  613.         n -= ran->ENo - ran->SNo + 1;
  614.     }
  615.     if (n < 0)
  616.     n = 0;
  617.     return(n);
  618. }
  619.  
  620.